package nl.rintcius.groovy

public class ExpandoDsl {
	
	Script script
	Binding binding
	boolean setRootProperty = false
	
	public ExpandoDsl(String scriptText) {
	    this(new GroovyShell().parse(scriptText))
	}
	
	public ExpandoDsl(Script script) {
		this.script = script
		this.binding = script.binding
		Expando root = new Expando()
		this.binding.setVariable("root", root)
		List stack = [root]
		this.binding.setVariable("stack", stack)
	}
	
	public Expando create() {
		def invokeMethod = { String name, args ->
			
			def metaMethod = delegate.metaClass.getMetaMethod(name, args)
			def result
			if (metaMethod) {
				result = metaMethod.invoke(delegate,args)
			} else {
				Expando e = new Expando()
				List stack = binding.getVariable("stack")
				Expando parent = stack.last()
				assert parent != null
				parent."$name" = e
				for (arg in args) {
					if (arg instanceof Closure) {
						Closure cl = arg
						cl.delegate = e
						cl.resolveStrategy = Closure.DELEGATE_FIRST
						stack.push(e)
						if (setRootProperty) {
						    cl.setProperty("root", binding.getVariable("root"))
						}
						cl.call()
						stack.pop()
					} else if (arg instanceof Map) {
					    arg.each() { k, v ->
					       e."$k" = v
					    }
					    
					} else {
					    e.value = arg
					    if (!e.valueList) {
					        e.valueList = []
					    }
					    e.valueList << arg
					}
				}
				result = stack.last()
			}
			result
		}
		script.metaClass.invokeMethod = invokeMethod
		return script.run()
	}
}
